package com.cheetah.start.common.plugin.log;

import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import cn.hutool.json.JSONUtil;
import com.cheetah.start.common.annotation.Log;
import com.cheetah.start.common.enums.LogTypeEnum;
import com.cheetah.start.common.utils.MyIpUtil;
import com.cheetah.start.common.utils.MyServletUtil;
import com.cheetah.start.common.utils.MyStrUtil;
import com.cheetah.start.monitor.log.domain.SysLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;

/**
 * @author xjh
 * @create 2021/7/4
 **/
@Aspect
@Component
@Slf4j
public class LogAspect {


    @Resource
    private LogFactory logFactory;

    /**
     * 切 面 编 程
     */
    @Pointcut("@annotation(com.cheetah.start.common.annotation.Log) || @within(com.cheetah.start.common.annotation.Log)")
    public void dsPointCut() {
    }

    /**
     * 处 理 系 统 日 志
     */
    @Around("dsPointCut()")
    private Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        SysLog sysLog = new SysLog();
        Object result;
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String classmethod = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
        UserAgent parse = UserAgentUtil.parse(request.getHeader("User-Agent"));
        try {
            Log loggingAnnotation = getLog(joinPoint);
            sysLog.setTitle(loggingAnnotation.title())
                    .setDescription(loggingAnnotation.describe())
                    .setBusinessType(loggingAnnotation.type().toString())
                    .setSuccess("true")
                    .setBrowser(parse.getBrowser().getName())
                    .setMethod(MyStrUtil.getSubStr(classmethod, 2, '.'))
                    .setRequestUrl(MyServletUtil.getRequestURI())
                    .setLoggingType(loggingAnnotation.logType().name())
                    .setRequestMethod(request.getMethod())
                    .setOperateAddress(MyIpUtil.getIpNotHavePort(request));
            if (loggingAnnotation.logType().equals(LogTypeEnum.LOGIN)) {
                sysLog.setOperateName(request.getParameter("name"))
                        .setCreateBy(request.getParameter("name"));
            } else {
                SaSession session = StpUtil.getSession();
                sysLog.setOperateName(session.getString("name"))
                        .setCreateBy(session.getString("name"));
            }
            sysLog.setRequestParam(Arrays.toString(joinPoint.getArgs()))
                    .setCreateTime(new Date())
                    .setRequestBody(MyServletUtil.getQueryParam())
                    .setSystemOs(parse.getOs().getName());
            result = joinPoint.proceed();
            sysLog.setResponseBody(JSONUtil.toJsonStr(result));
        } catch (Exception exception) {
            sysLog.setSuccess("false");
            sysLog.setErrorMsg(exception.getMessage());
            throw exception;
        } finally {
            logFactory.record(sysLog);
        }
        return result;
    }

    /**
     * 获 取 注 解
     */
    public Log getLog(ProceedingJoinPoint point) {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Class<? extends Object> targetClass = point.getTarget().getClass();
        Log targetLogging = targetClass.getAnnotation(Log.class);
        if (targetLogging != null) {
            return targetLogging;
        } else {
            Method method = signature.getMethod();
            return method.getAnnotation(Log.class);
        }
    }
}
